package beans;

import java.sql.*;
import java.util.*;

import utils.Validador;
import bd.*;
import mapping.Enlace;
import mapping.UrlEnlace;

public class BeanEnlaces {

	public int contadorTuplas;

	public BeanEnlaces() {
		super();
	}

	/* CONSULTAS */

	public Enlace getEnlacePorId(String id_enlace) {
		StringBuffer query = new StringBuffer(
				"SELECT * FROM enlaces NATURAL JOIN tipo_enlace ");
		query.append(" WHERE id_enlace = " + id_enlace);
		ResultSet rsEnlace = null;
		Enlace enlace = new Enlace();
		try {
			rsEnlace = GestorBD.consulta(query);
			if (rsEnlace != null) {
				while (rsEnlace.next()) {
					enlace = new Enlace(Integer.parseInt(id_enlace), rsEnlace
							.getString("enlace"), rsEnlace
							.getString("tipo_enlace"));
					// con getUrlsEnlace obtenemos la lista de URLs
					// del enlace dado su id
					enlace.setListaUrls(getUrlsEnlace(Integer
							.parseInt(id_enlace)));
				}
			}
			rsEnlace.close();
		} catch (Exception e) {
			System.err
					.println("##### ERROR EN getEnlacePorId: " + e.toString());
		}
		return enlace;
	}

	/**
	 * Obtiene una lista de todos los enlaces seg�n los par�metros recibidos
	 * 
	 * @param tipoEnlace
	 * @param nombreEnlace
	 * @return
	 * @throws Exception
	 */
	public List getEnlaces(String nombreEnlace, String[] tipoEnlace,
			String urlenlace) throws Exception {
		List listaEnlaces = new LinkedList();
		StringBuffer query = new StringBuffer(
				"SELECT * FROM enlaces e NATURAL JOIN tipo_enlace te");

		// if (!urlenlace.equals(""))
		if (urlenlace.length() != 0)
			query.append(", url_enlace ue");

		if (nombreEnlace.length() != 0 || tipoEnlace != null
				|| urlenlace.length() != 0) {
			query.append(" WHERE ");
		}
		// BUSQUEDA POR NOMBRE
		// se pone entre % para que busque aquellas palabras
		// que contengan la subcadena nombre
		if (nombreEnlace.length() != 0) {
			query.append(" e.enlace LIKE '%" + nombreEnlace + "%'");
		}
		// BUSQUEDA POR TIPOS
		if (tipoEnlace != null) {
			if (nombreEnlace.length() != 0)
				query.append(" AND ");
			for (int i = 0; i < tipoEnlace.length - 1; i++) {
				query.append("e.id_tipo_enlace = " + tipoEnlace[i] + " OR ");
			}
			query.append("e.id_tipo_enlace = "
					+ tipoEnlace[tipoEnlace.length - 1]);
		}
		// BUSQUEDA POR URL
		if (urlenlace.length() != 0) {
			if (nombreEnlace.length() != 0 || tipoEnlace != null)
				query.append(" AND ");
			query.append("e.id_enlace = ue.id_enlace AND ue.url_enlace LIKE '%"
					+ urlenlace + "%'");
			query.append(" GROUP BY e.id_enlace");
		}
		// finalmente devolvemos los resultados ordenados por nombre
		query.append(" ORDER BY e.enlace;");
		// pasamos a hacer la consulta
		ResultSet rsEnlaces = null;
		try {
			rsEnlaces = GestorBD.consulta(query);
			if (rsEnlaces != null) {
				while (rsEnlaces.next()) {
					Enlace enl = new Enlace(rsEnlaces.getInt("id_enlace"),
							rsEnlaces.getString("enlace"), rsEnlaces
									.getString("tipo_enlace"));
					// con getUrlsEnlace obtenemos la lista de URLs
					// del enlace dado su id
					enl.setListaUrls(getUrlsEnlace(rsEnlaces
							.getInt("id_enlace")));
					System.out.println("===== ENLACE: " + enl);
					// finalmente a�adimos el enlace a la lista
					listaEnlaces.add(enl);
				}
			}
			rsEnlaces.close();
		} catch (ConsultaInadecuadaException cie) {
			cie.printStackTrace();
			throw new ConsultaInadecuadaException("### ERROR EN getEnlaces "
					+ cie.toString());
		} catch (SQLException sqle) {
			sqle.printStackTrace();
			throw new ConsultaInadecuadaException("### ERROR EN getEnlaces "
					+ sqle.toString());
		} catch (NullPointerException npe) {
			npe.printStackTrace();
			throw new ConsultaInadecuadaException("### ERROR EN getEnlaces "
					+ npe.toString());
		} catch (Exception e) {
			e.printStackTrace();
			throw new ConsultaInadecuadaException("### ERROR EN getEnlaces "
					+ e.toString());
		}
		return listaEnlaces;
	}

	public List getEnlaces(String nombreEnlace, String[] tipoEnlace,
			String urlenlace, int cantidadTuplas, int cursor) throws Exception {
		List listaEnlaces = new LinkedList();
		StringBuffer queryCount = new StringBuffer("SELECT COUNT(*) ");
		StringBuffer query = new StringBuffer("SELECT * ");
		StringBuffer subquery = new StringBuffer(
				" FROM enlaces e NATURAL JOIN tipo_enlace te");

		// if (!urlenlace.equals(""))
		if (urlenlace.length() != 0)
			subquery.append(", url_enlace ue");

		if (nombreEnlace.length() != 0 || tipoEnlace != null
				|| urlenlace.length() != 0) {
			subquery.append(" WHERE ");
		}
		// BUSQUEDA POR NOMBRE
		// se pone entre % para que busque aquellas palabras
		// que contengan la subcadena nombre
		if (nombreEnlace.length() != 0) {
			subquery.append(" e.enlace LIKE '%" + nombreEnlace + "%'");
		}
		// BUSQUEDA POR TIPOS
		if (tipoEnlace != null) {
			if (nombreEnlace.length() != 0)
				subquery.append(" AND ");
			for (int i = 0; i < tipoEnlace.length - 1; i++) {
				subquery.append("e.id_tipo_enlace = " + tipoEnlace[i] + " OR ");
			}
			subquery.append("e.id_tipo_enlace = "
					+ tipoEnlace[tipoEnlace.length - 1]);
		}
		// BUSQUEDA POR URL
		if (urlenlace.length() != 0) {
			if (nombreEnlace.length() != 0 || tipoEnlace != null)
				subquery.append(" AND ");
			subquery
					.append("e.id_enlace = ue.id_enlace AND ue.url_enlace LIKE '%"
							+ urlenlace + "%'");
			subquery.append(" GROUP BY e.id_enlace");
		}
		// finalmente devolvemos los resultados ordenados por nombre
		subquery.append(" ORDER BY e.enlace;");

		query.append(subquery);
		queryCount.append(subquery);

		// pasamos a hacer la consulta
		ResultSet rsEnlaces = null;
		try {
			ResultSet rsContLugares = GestorBD.consulta(queryCount);
			if (rsContLugares.next()) {
				contadorTuplas = rsContLugares.getInt(1);
			}
			rsEnlaces = GestorBD.consulta(query);
			if (rsEnlaces != null) {
				if (cursor > 0)
					rsEnlaces.absolute(cursor);
				int i = 0;
				while (rsEnlaces.next() && i < cantidadTuplas) {
					Enlace enl = new Enlace(rsEnlaces.getInt("id_enlace"),
							rsEnlaces.getString("enlace"), rsEnlaces
									.getString("tipo_enlace"));
					// con getUrlsEnlace obtenemos la lista de URLs
					// del enlace dado su id
					enl.setListaUrls(getUrlsEnlace(rsEnlaces
							.getInt("id_enlace")));
					System.out.println("===== ENLACE: " + enl);
					// finalmente a�adimos el enlace a la lista
					listaEnlaces.add(enl);
					i++;
				}
			}
			rsEnlaces.close();
		} catch (ConsultaInadecuadaException cie) {
			cie.printStackTrace();
			throw new ConsultaInadecuadaException("### ERROR EN getEnlaces "
					+ cie.toString());
		} catch (SQLException sqle) {
			sqle.printStackTrace();
			throw new ConsultaInadecuadaException("### ERROR EN getEnlaces "
					+ sqle.toString());
		} catch (NullPointerException npe) {
			npe.printStackTrace();
			throw new ConsultaInadecuadaException("### ERROR EN getEnlaces "
					+ npe.toString());
		} catch (Exception e) {
			e.printStackTrace();
			throw new ConsultaInadecuadaException("### ERROR EN getEnlaces "
					+ e.toString());
		}
		return listaEnlaces;
	}

	/**
	 * Devuelve la lista con todos los tipos existentes en la BD
	 * 
	 * @return
	 */
	public List getTipoEnlaces() {
		List listTipoEnlaces = new LinkedList();
		ResultSet rsTipoEnlaces = null;
		StringBuffer query = new StringBuffer("SELECT * FROM tipo_enlace");
		try {
			rsTipoEnlaces = GestorBD.consulta(query);
			while (rsTipoEnlaces.next()) {
				/*
				 * Tomamos la segunda columna (ColumnIndex = '2'), La primera
				 * columna tiene Id's que nos interesa para relacionar el tipo
				 * de lugar segun FK.Para entender por qu� se ha usado el
				 * formato: [id_tipo],[nom_tipo] Ir a AnadirLugar.jsp y ver
				 * metodo split de String Podria haberse usado arrays de dos
				 * elementos(almacenandolos en la lista); uno para el id y otro
				 * para el nombre del tipo de lugar asociado pero seria mas
				 * ineficiente en uso de memoria.
				 */
				listTipoEnlaces.add(rsTipoEnlaces.getString(1) + ","
						+ rsTipoEnlaces.getString(2));
			}
			rsTipoEnlaces.close();
		} catch (ConsultaInadecuadaException cie) {
			System.err.println("### CONSULTA Inadecuada en getTipoEnlaces");
		} catch (SQLException e1) {
			System.err.println("#### ERROR EN getTipoEnlaces");
		} catch (Exception e) {
			System.err.println("### Error Desconocido en getTipoEnlaces!");
		}
		return listTipoEnlaces;
	}

	public List getUrlsEnlace(int idEnlace) {
		List listaUrls = new LinkedList();
		ResultSet rsUrlEnlace = null;
		StringBuffer query = new StringBuffer(
				"SELECT * FROM url_enlace ue NATURAL JOIN enlaces e ");
		query.append(" WHERE ue.id_enlace = ");
		query.append(new Integer(idEnlace) + ";");
		try {
			rsUrlEnlace = GestorBD.consulta(query);
			while (rsUrlEnlace.next()) {
				UrlEnlace ue = new UrlEnlace(rsUrlEnlace
						.getInt("id_url_enlace"), rsUrlEnlace
						.getString("url_enlace"), rsUrlEnlace
						.getString("descripcion_url"), idEnlace);
				listaUrls.add(ue);
			}
			rsUrlEnlace.close();
		} catch (ConsultaInadecuadaException cie) {
			System.err.println("### CONSULTA Inadecuada en getTipoEnlaces: "
					+ cie.toString());
		} catch (SQLException e1) {
			System.err
					.println("#### ERROR EN getTipoEnlaces: " + e1.toString());
		} catch (Exception e) {
			System.err.println("### Error Desconocido en getTipoEnlaces: "
					+ e.toString());
		}
		return listaUrls;
	}

	/** INSERCIONES * */

	/**
	 * Inserta un enlace
	 * 
	 * @param params:
	 *            lista de parametros
	 * @param urls:
	 *            lista de URLs asociadas
	 * @return
	 * @throws Exception
	 */
	public boolean insertaEnlace(List params, LinkedList urls) throws Exception {
		StringBuffer query = new StringBuffer(
				"INSERT INTO enlaces(enlace, id_tipo_enlace) VALUES (?,?)");
		precondicionEnlaces(params, urls);
		try {
			GestorBD.comenzarTransaccion();
			int id_enlace = GestorBD.inserta(query, params);
			System.out.println("Id del nuevo enlace: " + id_enlace);
			// insertamos la lista de URLs
			insertaUrl(urls, id_enlace);
			GestorBD.hacerCommit();
		} catch (Exception e) {
			throw new Exception("error en inserta enlace " + e.toString());
		}
		return true;
	}

	/**
	 * Inserta la lista de URLs asociadas a un id_enlace dado
	 * 
	 * @param urls
	 * @param id_enlace
	 * @throws NullPointerException
	 * @throws Exception
	 */
	private void insertaUrl(List urls, int id_enlace)
			throws NullPointerException, Exception {
		StringBuffer query = new StringBuffer(
				"INSERT INTO url_enlace(url_enlace, descripcion_url, id_enlace) VALUES (?,?,?)");
		if (id_enlace == -1) {
			throw new NullPointerException("El id_enlace no existe");
		}
		// insertamos las URLs en iterando sobre la lista
		if (urls != null) {
			Iterator it = urls.listIterator();
			while (it.hasNext()) {
				UrlEnlace url = (UrlEnlace) it.next();
				String[] param = { url.getUrl_enlace(),
						url.getDescripcion_url(), String.valueOf(id_enlace) };
				GestorBD.inserta(query, param);
			}
		}
	}

	/** ACTUALIZACIONES * */
	public boolean actualizaEnlace(List params, String id_enlace,
			List listaUrls, String listaUrlsEliminar) throws Exception {
		StringBuffer query = new StringBuffer(
				"UPDATE enlaces SET enlace = ?, id_tipo_enlace = ?");
		query.append(" WHERE id_enlace = " + id_enlace);
		precondicionEnlaces(params, listaUrls);
		try {
			GestorBD.comenzarTransaccion();
			GestorBD.actualiza(query, params);
			actualizaUrlsLista(listaUrls, id_enlace);
			borraListaUrls(listaUrlsEliminar);
			GestorBD.hacerCommit();
		} catch (Exception e) {
			throw new Exception(e.toString());
		}
		return true;
	}

	/**
	 * 
	 * @param listaUrls
	 * @param id_enlace
	 * @throws Exception
	 */
	private void actualizaUrlsLista(List listaUrls, String id_enlace)
			throws Exception {
		Iterator it = listaUrls.iterator();
		while (it.hasNext()) {
			UrlEnlace url = (UrlEnlace) it.next();
			try {
				/*
				 * si la url est� entre las existentes, es decir, el idurl != 0 ->
				 * actualiza
				 */
				if (url.getId_url_enlace() != 0) {
					System.out.println("Existo: " + url);
					StringBuffer queryUpd = new StringBuffer(
							"UPDATE url_enlace SET url_enlace = ?, descripcion_url = ?");
					queryUpd.append(" WHERE id_url_enlace =?;");
					String[] paramsUpd = { url.getUrl_enlace(),
							url.getDescripcion_url(),
							String.valueOf(url.getId_url_enlace()) };
					GestorBD.actualiza(queryUpd, paramsUpd);
					System.out.println("Actualizada " + url);
				}
				// sino, inserta una nueva url
				else {
					System.out.println("No existo: " + url);
					StringBuffer queryIns = new StringBuffer(
							"INSERT INTO url_enlace (url_enlace, descripcion_url, id_enlace) VALUES (?,?,?);");
					String[] paramsIns = { url.getUrl_enlace(),
							url.getDescripcion_url(), id_enlace };
					GestorBD.inserta(queryIns, paramsIns);
					System.out.println("Insertada " + url);
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception("Error en actualizaUrlsLista: "
						+ e.toString());
			}
		}
	}

	/**
	 * 
	 * @param listaUrls
	 * @throws Exception
	 */
	private void borraListaUrls(String listaUrls) throws Exception {
		StringBuffer query = new StringBuffer(
				"DELETE FROM url_enlace WHERE id_url_enlace = ?;");
		if (listaUrls.length() > 0) {
			String idsUrls[] = listaUrls.split(",");
			try {
				GestorBD.borra(query, idsUrls);
				System.out.println("Borradas ");
			} catch (NullPointerException e) {
				e.printStackTrace();
				throw new NullPointerException(e.toString());
			} catch (ConsultaInadecuadaException e) {
				e.printStackTrace();
				throw new ConsultaInadecuadaException(e.toString());
			} catch (SQLException e) {
				e.printStackTrace();
				throw new SQLException(e.toString());
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception(e.toString());
			}
		}
	}

	/** BORRADO * */

	/**
	 * 
	 * @param enlaces
	 * @return Booleano que indica si el borrado ha sido satisfactorio
	 * @throws Exception
	 */
	public boolean borraEnlaces(String[] enlaces) throws Exception {
		StringBuffer queryBorrEnl = new StringBuffer(
				"DELETE FROM enlaces WHERE id_enlace = ?;");
		try {
			// NOTA: no hace faltaborrar las URLs aparte
			// pq la tabla es ON DELETE CASCADE
			GestorBD.borra(queryBorrEnl, enlaces);
		} catch (NullPointerException e) {
			e.printStackTrace();
			throw new NullPointerException(e.toString());
		} catch (ConsultaInadecuadaException e) {
			e.printStackTrace();
			throw new ConsultaInadecuadaException(e.toString());
		} catch (SQLException e) {
			e.printStackTrace();
			throw new SQLException(e.toString());
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception(e.toString());
		}
		return true;
	}

	private void precondicionEnlaces(List params, List urls)
			throws NullPointerException, Exception {
		if (params == null || params.isEmpty()) {
			throw new NullPointerException("Los parametros son vacios");
		}
		// si el nombre del enlace es vacio --> error
		String enlace = (String) params.get(0);
		if (enlace == null || enlace.length() == 0) {
			throw new NullPointerException("El enlace no puede ser vac�o");
		}
		// si la lista de urls es vacia --> error
		if (urls == null || urls.isEmpty()) {
			throw new NullPointerException(
					"La lista de URLs es vacia, un enlace debe tener al menos una URL asociada");
		}
		// comprueba que las URLs recibidas no son erroneas
		Iterator it = urls.iterator();
		while (it.hasNext()) {
			UrlEnlace url = (UrlEnlace) it.next();
			if (!Validador.esURLValido(url.getUrl_enlace())) {
				throw new Exception("La URL: " + url.getUrl_enlace()
						+ " no es valida");
			}
		}
	}

	public void conectar() {
		try {
			GestorBD.conectar();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void desconectar() {
		try {
			GestorBD.desconectar();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
